#ifndef ALI_NAND_H
#define ALI_NAND_H

#include<hld/hld_dev.h>

#define MAX_PARTITION_NUM	20
#define ALI_NAND_PART_0		0x0
#define ALI_NAND_PART_1		0x1
#define ALI_NAND_PART_2		0x2
#define ALI_NAND_PART_3		0x3
#define ALI_NAND_PART_4		0x4
#define ALI_NAND_PART_5		0x5
#define ALI_NAND_PART_6		0x6
#define ALI_NAND_PART_7		0x7
#define ALI_NAND_PART_8		0x8
#define ALI_NAND_PART_9		0x9
#define ALI_NAND_PART_10	0xa
#define ALI_NAND_PART_11	0xb
#define ALI_NAND_PART_ALL	0xFF

#define INVALID_BLK_NUM	0xFFFFFFFF

/* The maximum number of NAND chips in an array */
#define NAND_MAX_CHIPS		8

/* This constant declares the max. oobsize / page, which
 * is supported now. If you add a chip with bigger oobsize/page
 * adjust this accordingly.
 */
#define NAND_MAX_OOBSIZE	512
#define NAND_MAX_PAGESIZE	8192

/*
 * Constants for Hardware ECC
 */
#define NAND_ECC_READ		0	/* Reset Hardware ECC for read */
#define NAND_ECC_WRITE		1	/* Reset Hardware ECC for write */
#define NAND_ECC_READSYN	2	/* Enable Hardware ECC before syndrom is read back from flash */

#define PMIPOS 	4

#define SUPPORT_4G


#define MAC_EN_MAGIC (0xdeadbeef)
//#define analy_tim

#if 0
	#define ALI_NAND_PRINTF		libc_printf
#else
	#define ALI_NAND_PRINTF(...)	do{}while(0)
#endif

#ifdef DEBUG_MTD
	#define ALI_NAND_DEBUG		libc_printf
#else
	#define ALI_NAND_DEBUG(...)	do{}while(0)
#endif

/* Type Define */
#define NULL    ((void *)0)

typedef long long      	loff_t;

#if 0
	#if (_MIPS_SZLONG == 32)
		typedef unsigned int	__kernel_size_t;
	#endif
	
	#if (_MIPS_SZLONG == 64)
		typedef unsigned long	__kernel_size_t;
	#endif
#endif

extern INT8 ali_nand_name[];


#ifdef analy_tim
#define read_c0_count()		__read_32bit_c0_register($9, 0)

#define __read_32bit_c0_register(source, sel)				\
({ int __res;								\
	if (sel == 0)							\
		__asm__ __volatile__(					\
			"mfc0\t%0, " #source "\n\t"			\
			: "=r" (__res));				\
	else								\
		__asm__ __volatile__(					\
			".set\tmips32\n\t"				\
			"mfc0\t%0, " #source ", " #sel "\n\t"		\
			".set\tmips0\n\t"				\
			: "=r" (__res));				\
	__res;								\
})



struct timer_info{
	int lba;
	int len;
	unsigned int cmd_start;
	unsigned int cmd_end;
	unsigned int rd_sec_start[128];
	unsigned int rd_sec_end[128];
	unsigned int rd_sec[128];
	unsigned int rd_mtd_start[128];
	unsigned int rd_mtd_end[128];
	unsigned int rd_mtd[128];
	unsigned int cp_buf_start[128];
	unsigned int cp_buf_end[128];
	unsigned int cp_buf[128];
	unsigned int create_ufunfish_job[128];
	int i;
};
#endif

struct ali_nand_parttition_info {
	UINT64 start;
	UINT64 len;
	UINT32 flags;
};

struct ali_nand_info {
	UINT32 pagesize;
	UINT32 blocksize;
	UINT32 numchips;
	UINT32 blockPerChip;
	UINT32 eccUnitSize;
	UINT64 startAddr;
	UINT32 partitionNum;
	struct ali_nand_parttition_info partInfo[MAX_PARTITION_NUM];
    unsigned long loader_start;
    unsigned long loader_len;
	unsigned long logo_start;
    unsigned long logo_len;
	unsigned long stmach_addr;      /* state machine */
    unsigned long envvar_addr;      /* uboot environment variable */
	unsigned long uboot_start;
    unsigned long uboot_len;
	unsigned long uboot_backup_start;
    unsigned long uboot_backup_len;
};

struct ali_nand_device
{
	struct hld_device   *next;						/* Next device structure */
	UINT32	type;						/* Interface hardware type */
	INT8	name[HLD_MAX_NAME_SIZE];	/* Device name */
	void	*priv;						/* pointer to private data */

	INT32	(*init)();
	INT32	(*open)(struct ali_nand_device *dev);
	INT32	(*close)(struct ali_nand_device *dev);
	// Physical Operation API (High Level) 
	int	(*read_partition)(struct ali_nand_device *dev, UINT32 partIdx, UINT8 *tarAddr, UINT32 size);
	int	(*write_partition)(struct ali_nand_device *dev, UINT32 partIdx, UINT8 *tarAddr, UINT32 size);
	int	(*scan_bad_blocks)(struct ali_nand_device *dev, UINT32* pBadBlockTable);

	// Physical Operation API (Low Level)
	void	(*get_nand_info)(struct ali_nand_device *dev, struct ali_nand_info *info);
	int	(*phy_read)(struct ali_nand_device *dev, UINT32 partIdx, UINT32 lba, UINT32 size, UINT8 *buf);
	int	(*phy_write)(struct ali_nand_device *dev, UINT32 partIdx, UINT32 lba, UINT32 size, UINT8 *buf);
	int	(*phy_write_bbt)(struct ali_nand_device *dev, UINT32 partIdx, UINT32 lba, UINT32 size, UINT8 *buf, BOOL isMirror);
	int	(*phy_erase)(struct ali_nand_device *dev, UINT32 partIdx, UINT32 lba, UINT32 size);
	int	(*block_isbad)(struct ali_nand_device *dev, UINT32 partIdx, UINT32 lba);
	int	(*block_markbad)(struct ali_nand_device *dev, UINT32 partIdx, UINT32 lba);

	// Logical Operation API
	int	(*open_ftl)(struct ali_nand_device *dev, UINT32 partIdx);
	int	(*logical_read)(struct ali_nand_device *dev, void *para, UINT32 lba, UINT32 size, UINT8 *buf);
	int	(*logical_write)(struct ali_nand_device *dev, void *para, UINT32 lba, UINT32 size, UINT8 *buf);
	int	(*logical_sync)(struct ali_nand_device *dev, void *para);
	UINT32	(*get_capacity)(struct ali_nand_device *dev, void *para);

	// API for updater use 
	INT32	(*open_updater)(struct ali_nand_device *dev);							//updater use only
	void	(*set_config)(struct ali_nand_device *dev, UINT8* buf);					//updater use only
	void	(*read_id)(struct ali_nand_device *dev, UINT8* pBuf, UINT8 bLen);			//updater use only
	int	(*scan_pmi_bbt)(struct ali_nand_device *dev);							//updater use only
};

RET_CODE ali_nand_attach(void);
RET_CODE ali_nand_open(struct ali_nand_device *dev);
RET_CODE ali_nand_close(struct ali_nand_device *dev);
RET_CODE ali_nand_detach(struct ali_nand_device *dev);
	
//===============   Physical Operation API (High Level)   ====================
int NF_LoadPartition (struct ali_nand_device *dev, UINT32 partIdx, UINT8 *tarAddr, UINT32 size);
int NF_SavePartition (struct ali_nand_device *dev, UINT32 partIdx, UINT8 *SrcAddr, UINT32 size);
int NF_ScanBadBlock(struct ali_nand_device *dev, UINT32* pBadBlockTable);  //for updater
int NF_LoadLoader(struct ali_nand_device *dev, loff_t offset, UINT8 *buf, UINT32 len);  //bootloader use only
int NF_SaveLoader(struct ali_nand_device *dev, loff_t offset, UINT8 *buf, UINT32 len);  //bootloader use only
int api_nand_pmi_check();
//===============   Physical Operation API (Low Level)   ====================
void NF_GetNandInfo (struct ali_nand_device *dev, struct ali_nand_info *info);
int NF_PhysicalRead (struct ali_nand_device *dev, UINT32 partIdx, UINT32 lba, UINT32 size, UINT8 *buf);
int NF_PhysicalWrite (struct ali_nand_device *dev, UINT32 partIdx, UINT32 lba, UINT32 size, UINT8 *buf);
int NF_PhysicalWriteBBT (struct ali_nand_device *dev, UINT32 partIdx, UINT32 lba, UINT32 size, UINT8 *buf, BOOL isMirror);
int NF_PhysicalErase (struct ali_nand_device *dev, UINT32 partIdx, UINT32 lba, UINT32 size);
int NF_BlockIsBad (struct ali_nand_device *dev, UINT32 partIdx, UINT32 lba);
int NF_BlockMarkBad (struct ali_nand_device *dev, UINT32 partIdx, UINT32 lba);
int NF_Init (struct ali_nand_device *dev);
void NF_Release (struct ali_nand_device *dev);

//===============   Physical Operation API (Low Level) for updater   ====================
void NF_SetNandConfig(struct ali_nand_device *dev, UINT8* buf);   //for updater
void NF_ReadID(struct ali_nand_device *dev, UINT8* pBuf, UINT8 bLen);   //for updater
int NF_Init_Simple (struct ali_nand_device *dev);   //for updater
int NF_Init_Rest (struct ali_nand_device *dev);   //for updater

//===============   Logical Operation API  ====================
int NF_LogicalRead (struct ali_nand_device *dev, void *para, UINT32 lba, UINT32 size, UINT8 *buf);
int NF_LogicalWrite (struct ali_nand_device *dev, void *para, UINT32 lba, UINT32 size, UINT8 *buf);
int NF_LogicalSync (struct ali_nand_device *dev, void *para);
UINT32 NF_GetCapacity (struct ali_nand_device *dev, void *para);
int NF_FTL_Init (struct ali_nand_device *dev, UINT32 partIdx);
void NF_FTL_Release (struct ali_nand_device *dev);

/* ATTENTION!!! Only support one page read at once */
int NF_PreRecLogicalRead (struct ali_nand_device *dev, UINT32 partIdx, UINT32 lba, UINT32 size, UINT8 *buf);
/* ATTENTION!!! Only support one page write at once */
int NF_PreRecLogicalWrite (struct ali_nand_device *dev, UINT32 partIdx, UINT32 lba, UINT32 size, UINT8 *buf);


/*
 * Constants for ECC_MODES
 */
typedef enum {
	NAND_ECC_NONE,
	NAND_ECC_SOFT,
	NAND_ECC_HW,
	NAND_ECC_HW_SYNDROME,
} nand_ecc_modes_t;


/*
 * oob operation modes
 *
 * MTD_OOB_PLACE:	oob data are placed at the given offset
 * MTD_OOB_AUTO:	oob data are automatically placed at the free areas
 *			which are defined by the ecclayout
 * MTD_OOB_RAW:		mode to read raw data+oob in one chunk. The oob data
 *			is inserted into the data. Thats a raw image of the
 *			flash contents.
 */
typedef enum {
	MTD_OOB_PLACE,
	MTD_OOB_AUTO,
	MTD_OOB_RAW,
} mtd_oob_mode_t;

struct nand_oobfree {
	UINT32 offset;
	UINT32 length;
};

#define MTD_MAX_OOBFREE_ENTRIES	8
/*
 * ECC layout control structure. Exported to userspace for
 * diagnosis and to allow creation of raw images
 */
struct nand_ecclayout {
	UINT32 eccbytes;
	UINT32 eccpos[64];
	UINT32 oobavail;
	struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];
};

/**
 * struct mtd_ecc_stats - error correction stats
 *
 * @corrected:	number of corrected bits
 * @failed:	number of uncorrectable errors
 * @badblocks:	number of bad blocks in this partition
 * @bbtblocks:	number of blocks reserved for bad block tables
 */
struct mtd_ecc_stats {
	UINT32 corrected;
	UINT32 failed;
	UINT32 badblocks;
	UINT32 bbtblocks;
};

/* Option constants for bizarre disfunctionality and real
*  features
*/
#define NAND_NO_AUTOINCR	0x00000001	/* Chip can not auto increment pages */
#define NAND_BUSWIDTH_16	0x00000002	/* Buswitdh is 16 bit */
#define NAND_NO_PADDING		0x00000004	/* Device supports partial programming without padding */
#define NAND_CACHEPRG		0x00000008	/* Chip has cache program function */
#define NAND_COPYBACK		0x00000010	/* Chip has copy back function */
#define NAND_IS_AND		0x00000020	/* AND Chip which has 4 banks and a confusing page / block
 						 * assignment. See Renesas datasheet for further information */
#define NAND_4PAGE_ARRAY	0x00000040	/* Chip has a array of 4 pages which can be read without
 						 * additional ready /busy waits */
#define BBT_AUTO_REFRESH	0x00000080	/* Chip requires that BBT is periodically rewritten to prevent
						 * bits from adjacent blocks from 'leaking' in altering data.
 						 * This happens with the Renesas AG-AND chips, possibly others.  */
#define NAND_NO_READRDY		0x00000100	/* Chip does not require ready check on read. True
						 * for all large page devices, as they do not support
 						 * autoincrement.*/
#define NAND_NO_SUBPAGE_WRITE	0x00000200	/* Chip does not allow subpage writes */


/* Options valid for Samsung large page devices */
#define NAND_SAMSUNG_LP_OPTIONS \
	(NAND_NO_PADDING | NAND_CACHEPRG | NAND_COPYBACK)

/* Macros to identify the above */
#define NAND_CANAUTOINCR(chip) (!(chip->options & NAND_NO_AUTOINCR))
#define NAND_MUST_PAD(chip) (!(chip->options & NAND_NO_PADDING))
#define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG))
#define NAND_HAS_COPYBACK(chip) ((chip->options & NAND_COPYBACK))
/* Large page NAND with SOFT_ECC should support subpage reads */
#define NAND_SUBPAGE_READ(chip) ((chip->ecc.mode == NAND_ECC_SOFT) \
					&& (chip->page_shift > 9))

/* Mask to zero out the chip options, which come from the id table */
#define NAND_CHIPOPTIONS_MSK	(0x0000ffff & ~NAND_NO_AUTOINCR)

/* chip->options */
/* Use a flash based bad block table. This option is passed to the
 * default bad block table function. */
#define NAND_USE_FLASH_BBT		0x00010000
/* This option skips the bbt scan during initialization. */
#define NAND_SKIP_BBTSCAN			0x00020000
/* This option is defined if the board driver allocates its own buffers
   (e.g. because it needs them DMA-coherent */
#define NAND_OWN_BUFFERS			0x00040000
/* Options set by nand scan */
/* Nand scan has allocated controller struct */
#define NAND_CONTROLLER_ALLOC		0x80000000

/* Status bits */
#define NAND_STATUS_FAIL	0x01
#define NAND_STATUS_FAIL_N1	0x02
#define NAND_STATUS_TRUE_READY	0x20
#define NAND_STATUS_READY	0x40
#define NAND_STATUS_WP		0x80

#define MTD_ERASE_PENDING      	0x01
#define MTD_ERASING		0x02
#define MTD_ERASE_SUSPEND	0x04
#define MTD_ERASE_DONE          0x08
#define MTD_ERASE_FAILED        0x10

#define MTD_FAIL_ADDR_UNKNOWN 	0xffffffff

struct erase_info {
	struct mtd_info *mtd;
	
	#ifdef SUPPORT_4G
		loff_t addr;
		loff_t len;
		loff_t fail_addr;
	#else	
		UINT32 addr;
		UINT32 len;
		UINT32 fail_addr;
	#endif
	
	UINT8	 state;
};

struct mtd_oob_ops {
	mtd_oob_mode_t	mode;
	UINT32		len;
	UINT32		retlen;
	UINT32		ooblen;
	UINT32		oobretlen;
	UINT32		ooboffs;
	UINT8		*datbuf;
	UINT8		*oobbuf;
};

struct mtd_info {
	#ifdef SUPPORT_4G		
		loff_t size;	 // Total size of the MTD
	#else
		UINT32 size;	 // Total size of the MTD
	#endif
	UINT32 erasesize;
	UINT32 writesize;
	UINT32 oobsize;   // Amount of OOB data per block (e.g. 16)
	UINT32 oobavail;  // Available OOB bytes per block

	/* ECC status information */
	struct mtd_ecc_stats ecc_stats;
	struct nand_ecclayout *ecclayout;   /* ecc layout structure pointer - read only ! */
	
	int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
	int (*read_oob) (struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops);
	int (*write_oob) (struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops);
	int (*read) (struct mtd_info *mtd, loff_t from, UINT32 len, UINT32 *retlen, UINT8 *buf);
	int (*write) (struct mtd_info *mtd, loff_t to, UINT32 len, UINT32 *retlen, const UINT8 *buf);

	/* Bad block management functions */
	int (*block_isbad) (struct mtd_info *mtd, loff_t ofs);
	int (*block_markbad) (struct mtd_info *mtd, loff_t ofs);
	void (*crypto_inhibit)(struct mtd_info *mtd, int inhibit);
	void *priv;
};

/*
 * nand_state_t - chip states
 * Enumeration for NAND flash chip state
 */
typedef enum {
	FL_READY,
	FL_READING,
	FL_WRITING,
	FL_ERASING,
	FL_SYNCING,
	FL_CACHEDPRG,
	FL_PM_SUSPENDED,
} nand_state_t;

enum{
	ECC_16=0,
	ECC_24=1,	
	ECC_1=2,
	CRC_MODE=3,
	EF_MODE=4,
	BA_MODE=5,
	ECC_24_SCRB=6,
	LBA_PNP=0,
};

/*
 * Constants for hardware specific CLE/ALE/NCE function
 *
 * These are bits which can be or'ed to set/clear multiple
 * bits in one go.
 */
/* Select the chip by setting nCE to low */
#define NAND_NCE		0x01
/* Select the command latch by setting CLE to high */
#define NAND_CLE		0x02
/* Select the address latch by setting ALE to high */
#define NAND_ALE		0x04
#define NAND_CTRL_CLE		(NAND_NCE | NAND_CLE)
#define NAND_CTRL_ALE		(NAND_NCE | NAND_ALE)
#define NAND_CTRL_CHANGE	0x80

/*
 * Standard NAND flash commands
 */
#define NAND_CMD_READ0		0
#define NAND_CMD_READ1		1
#define NAND_CMD_RNDOUT		5
#define NAND_CMD_PAGEPROG	0x10
#define NAND_CMD_READOOB	0x50
#define NAND_CMD_ERASE1		0x60
#define NAND_CMD_STATUS		0x70
#define NAND_CMD_STATUS_MULTI	0x71
#define NAND_CMD_SEQIN		0x80
#define NAND_CMD_RNDIN		0x85
#define NAND_CMD_READID		0x90
#define NAND_CMD_ERASE2		0xd0
#define NAND_CMD_RESET		0xff

/* Extended commands for large page devices */
#define NAND_CMD_READSTART	0x30
#define NAND_CMD_RNDOUTSTART	0xE0
#define NAND_CMD_CACHEDPROG	0x15

/* Extended commands for AG-AND device */
/*
 * Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but
 *       there is no way to distinguish that from NAND_CMD_READ0
 *       until the remaining sequence of commands has been completed
 *       so add a high order bit and mask it off in the command.
 */
#define NAND_CMD_DEPLETE1	0x100
#define NAND_CMD_DEPLETE2	0x38
#define NAND_CMD_STATUS_MULTI	0x71
#define NAND_CMD_STATUS_ERROR	0x72
/* multi-bank error status (banks 0-3) */
#define NAND_CMD_STATUS_ERROR0	0x73
#define NAND_CMD_STATUS_ERROR1	0x74
#define NAND_CMD_STATUS_ERROR2	0x75
#define NAND_CMD_STATUS_ERROR3	0x76
#define NAND_CMD_STATUS_RESET	0x7f
#define NAND_CMD_STATUS_CLEAR	0xff

#define NAND_CMD_NONE		-1

/* Status bits */
#define NAND_STATUS_FAIL	0x01
#define NAND_STATUS_FAIL_N1	0x02
#define NAND_STATUS_TRUE_READY	0x20
#define NAND_STATUS_READY	0x40
#define NAND_STATUS_WP		0x80

/* Keep gcc happy */
struct nand_chip;

struct nand_ecc_ctrl {
	nand_ecc_modes_t	mode;
	int			steps;
	int			size;
	int			bytes;
	//int			total;	//no use
	//int			prepad;   //no use
	//int			postpad;	//no use
	struct nand_ecclayout	*layout;
	void	(*hwctl)(struct mtd_info *mtd, int mode, UINT8 *buf);   
	int	(*calculate)(struct mtd_info *mtd,   //not support
			     const UINT8 *dat, UINT8 *ecc_code);
	int	(*correct)(struct mtd_info *mtd, UINT8 *dat,   //not support
			   UINT8 *read_ecc, UINT8 *calc_ecc);
	int	(*read_page_raw)(struct mtd_info *mtd,
			 struct nand_chip *chip, UINT8 *buf);
	void	(*write_page_raw)(struct mtd_info *mtd,
			  struct nand_chip *chip, const UINT8 *buf);
	int	(*read_page)(struct mtd_info *mtd, struct nand_chip *chip,
			     UINT8 *buf);
	int	(*read_subpage)(struct mtd_info *mtd,   //not support
			 struct nand_chip *chip, UINT32 offs, UINT32 len, UINT8 *buf);
	void	(*write_page)(struct mtd_info *mtd,
		      struct nand_chip *chip, const UINT8 *buf);
	int	(*read_oob)(struct mtd_info *mtd,
		    struct nand_chip *chip, int page, int sndcmd);
	int	(*write_oob)(struct mtd_info *mtd, struct nand_chip *chip, int page);
};

/**
 * struct nand_buffers - buffer structure for read/write
 * @ecccalc:	buffer for calculated ecc
 * @ecccode:	buffer for ecc read from flash
 * @databuf:	buffer for data - dynamically sized
 *
 * Do not change the order of buffers. databuf and oobrbuf must be in
 * consecutive order.
 */
struct nand_buffers {
	UINT8	ecccalc[NAND_MAX_OOBSIZE];	
	UINT8	ecccode[NAND_MAX_OOBSIZE];
	UINT8 	databuf[NAND_MAX_PAGESIZE+NAND_MAX_OOBSIZE];
};

struct nand_chip {
	nand_state_t	state;
	unsigned int	options;
	
	int	chip_shift;
	int	phys_erase_shift;
	int	bbt_erase_shift;
	int	page_shift;	
	int	numchips;
	int 	page_all_FF;
	int 	program_times;
	int     badblockpos;
	int 	crypto_mode;
	
	#ifdef SUPPORT_4G
		loff_t	chipsize;   //each chip size
	#else
		UINT32	chipsize;   //each chip size
	#endif
	UINT32 	blocks_perchip;
	UINT32 	pages_perblock;
	UINT32	bytes_perpage;
	UINT32  row_addr_cnt; 
	UINT32  read_clock;
	UINT32  write_clock;

	UINT32 	PMIpos;
	UINT32	partitionNum;   //LYH
	UINT32	startAddr;   	//LYH
	UINT32	badblock_sector;
	UINT32	badblock_len;

	UINT32	bbtMaxBlock;
	UINT8	*bbt;
	struct nand_bbt_descr	*bbt_td;
	struct nand_bbt_descr	*bbt_md;

	UINT32	ecctype;
	struct nand_ecc_ctrl ecc;

	int	subpagesize;
	int	pagebuf;
	struct 	nand_buffers *buffers;
	struct 	mtd_oob_ops ops;
	int	chip_delay;
	UINT8	*oob_poi;
	void	(*select_chip)(struct mtd_info *mtd, int chip);
	void	(*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);
	int	(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this);
	void	(*erase_cmd)(struct mtd_info *mtd, int page);
	int	(*block_markbad)(struct mtd_info *mtd, loff_t ofs);
	void	(*crypto_inhibit)(struct mtd_info *mtd, int inhibit);
	UINT8	(*read_byte)(struct mtd_info *mtd);
	int	(*write_page)(struct mtd_info *mtd, struct nand_chip *chip, const UINT8 *buf, int page, int cached, int raw);
	void	(*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
	void	(*write_buf)(struct mtd_info *mtd, const UINT8 *buf, int len);
	void	(*read_buf)(struct mtd_info *mtd, UINT8 *buf, int len);
	int	(*scan_bbt)(struct mtd_info *mtd);
	int	(*verify_buf)(struct mtd_info *mtd, const UINT8 *buf, int len);   //only function body, not implement yet
	int	(*block_bad)(struct mtd_info *mtd, loff_t ofs);   
	
	int	(*dev_ready)(struct mtd_info *mtd);   //not implement yet
	int	(*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page);   //not implement yet
	void	*priv;
	unsigned long loader_start;
    unsigned long loader_len;
    unsigned long logo_start;
    unsigned long logo_len;
	unsigned long stmach_addr;      /* state machine */
    unsigned long envvar_addr;      /* uboot environment variable */
	unsigned long uboot_start;
    unsigned long uboot_len;
	unsigned long uboot_backup_start;
    unsigned long uboot_backup_len;
};

#define FLASH_BBT_BLK_GOOD			0x3
#define FLASH_BBT_BLK_BAD			0x2
#define FLASH_BBT_BLK_BBT			0x1
#define FLASH_BBT_BLK_DEFAULT_BAD		0x0

#define RAM_BBT_BLK_GOOD			0x0
#define RAM_BBT_BLK_BAD				0x1
#define RAM_BBT_BLK_BBT				0x2
#define RAM_BBT_BLK_DEFAULT_BAD			0x3

struct nand_bbt_descr {
	int	options;
	int	pages[NAND_MAX_CHIPS];
	int	offs;
	int	veroffs;
	UINT8	version[NAND_MAX_CHIPS];
	int	len;
	int	maxblocks;
	int	reserved_block_code;
	UINT8	*pattern;
};

/* Options for the bad block table descriptors */

/* The number of bits used per block in the bbt on the device */
#define NAND_BBT_NRBITS_MSK	0x0000000F
#define NAND_BBT_1BIT		0x00000001
#define NAND_BBT_2BIT		0x00000002
#define NAND_BBT_4BIT		0x00000004
#define NAND_BBT_8BIT		0x00000008
#define	NAND_BBT_LASTBLOCK	0x00000010	/* The bad block table is in the last good block of the device */
#define NAND_BBT_ABSPAGE	0x00000020	/* The bbt is at the given page, else we must scan for the bbt */
#define NAND_BBT_SEARCH		0x00000040	/* The bbt is at the given page, else we must scan for the bbt */
#define NAND_BBT_PERCHIP	0x00000080	/* bbt is stored per chip on multichip devices */
#define NAND_BBT_VERSION	0x00000100	/* bbt has a version counter at offset veroffs */
#define NAND_BBT_CREATE		0x00000200	/* Create a bbt if none axists */
#define NAND_BBT_SCANALLPAGES	0x00000400	/* Search good / bad pattern through all pages of a block */	
//#define NAND_BBT_SCANEMPTY	0x00000800      /* Scan block empty during good / bad block scan */
#define NAND_BBT_WRITE		0x00001000	/* Write bbt if neccecary */
//#define NAND_BBT_SAVECONTENT	0x00002000      /* Read and write back block contents when writing bbt */ //no support
#define NAND_BBT_SCAN2NDPAGE	0x00004000	/* Search good / bad pattern on the first and the second page */

/* The maximum number of blocks to scan for a bbt */
#define NAND_BBT_SCAN_MAXBLOCKS	4

struct ali_nand_host {
	struct mtd_info	mtd;
	struct nand_chip	nand;
	struct mtd_partition	*parts;   //not fully support partition
	struct mtd_info *part_mtd[MAX_PARTITION_NUM];
	UINT8	*dmabuf1;
	UINT8	*dmaaddr1;   //dma_addr_t
	
	UINT32	base_addr;
	UINT32	chip_id;
	UINT8	chip_package;
	UINT8	chip_ver;
};

struct mtd_partition {
	char *name;				/* identifier string */
	unsigned long long size;		/* partition size */
	unsigned long long offset;		/* offset within the master MTD space */
	UINT32 mask_flags;			/* master MTD flags to mask out for this partition */
	struct nand_ecclayout *ecclayout;	/* out of band layout for this partition (NAND only)*/
	struct mtd_info **mtdp;			/* pointer to store the MTD object */
};

/* MTD flags for mtd_partition */
#define MTD_WRITEABLE		0x400	/* Device is writeable */
#define MTD_BIT_WRITEABLE	0x800	/* Single bits can be flipped */
#define MTD_NO_ERASE		0x1000	/* No erase necessary */
#define MTD_POWERUP_LOCK	0x2000	/* Always locked after reset */
#define MTD_DO_FTL		0x08	/* Do flash management for this partition */   // LYH 101227#1

/* Partition Flag on PMI */
#define PMI_PART_FLAG_SFT	30
#define PMI_PART_FLAG_MSK	0x3
#define PMI_PART_FLAG_FTL	0x1

static UINT8 bbt_pattern[] = {'B', 'b', 't', '0' };
static UINT8 mirror_pattern[] = {'1', 't', 'b', 'B' };

static struct nand_ecclayout ali_nand_hw_eccoob_1 = {
	.oobavail	= 6,
	.oobfree = {{0, 6}},
};

static struct nand_ecclayout ali_nand_hw_eccoob_16 = {
	.oobavail = 8,	
	.oobfree = {{0,8}}
};

static struct nand_ecclayout ali_nand_hw_eccoob_24 = {	
	.oobavail = 8,	
	.oobfree = {{0,8}}
};


/**
 * ffs - find first bit set
 * @x: the word to search
 *
 * This is defined the same way as
 * the libc and compiler builtin ffs routines, therefore
 * differs in spirit from the above ffz (man ffs).
 */
static inline int ffs(int x)
{
	int r = 1;

	if (!x)
		return 0;
	if (!(x & 0xffff)) {
		x >>= 16;
		r += 16;
	}
	if (!(x & 0xff)) {
		x >>= 8;
		r += 8;
	}
	if (!(x & 0xf)) {
		x >>= 4;
		r += 4;
	}
	if (!(x & 3)) {
		x >>= 2;
		r += 2;
	}
	if (!(x & 1)) {
		x >>= 1;
		r += 1;
	}
	return r;
}

/*
 * ..and if you can't take the strict
 * types, you can specify one yourself.
 *
 * Or not use min/max/clamp at all, of course.
 */
#define min_t(type, x, y) ({			\
	type __min1 = (x);			\
	type __min2 = (y);			\
	__min1 < __min2 ? __min1: __min2; })

#define max_t(type, x, y) ({			\
	type __max1 = (x);			\
	type __max2 = (y);			\
	__max1 > __max2 ? __max1: __max2; })
	
/*
 * min()/max()/clamp() macros that also do
 * strict type-checking.. See the
 * "unnecessary" pointer comparison.
 */
#define min(x, y) ({				\
	typeof(x) _min1 = (x);			\
	typeof(y) _min2 = (y);			\
	(void) (&_min1 == &_min2);		\
	_min1 < _min2 ? _min1 : _min2; })

#define max(x, y) ({				\
	typeof(x) _max1 = (x);			\
	typeof(y) _max2 = (y);			\
	(void) (&_max1 == &_max2);		\
	_max1 > _max2 ? _max1 : _max2; })

extern int ali_nand_default_bbt(struct mtd_info *mtd);
extern int ali_nand_read(struct mtd_info *mtd, loff_t from, UINT32 len, UINT32 *retlen, UINT8 *buf);
extern struct mtd_part *add_one_partition(struct mtd_info *master, const struct mtd_partition *part, int partno);
extern struct ali_nand_info g_nand_info;  /* Nand flash info */
#endif

